package de.fzi.kasma.learner.function.prediction;

import java.util.ArrayList;
import java.util.List;

import de.fzi.kasma.learner.data.Data;
import de.fzi.kasma.learner.data.Dataset;
import de.fzi.kasma.learner.data.Label;
import de.fzi.kasma.learner.function.kernel.HypothesisKernel;
import de.fzi.kasma.learner.function.kernel.Matrix;

public class EvoSVMPredictionFunction extends PredictionFunction{
	

	HypothesisKernel kernel;
	Dataset dataset;
	double complexity;
	Integer[] supportVectors;
	Double[] alphas;
//	double b;
	Matrix m;

	public double getComplexity() {
		return complexity;
	}

	public EvoSVMPredictionFunction(Dataset d,HypothesisKernel k, double[] cfs) throws Exception
	{
		this.kernel = k;
		this.dataset = d;
		m = kernel.calculateMatrix(dataset);
		this.complexity = k.getComplexity();
		setAlphas(cfs);
//		setBias();


	}
	
	/** 
	 * find the bias b for the Prediction function:  sgn( sum (y(i)*alpha(i)*K(x(i); x)) + b)
	 * b = y(k) - sum(y(i)*alpha(i)*K(x(i); x(k))) for any k (0 < alpha(k) < C)
	 **/
	
//	private void setBias() {
//
//        Data[] orderedData = dataset.getAllData();
//		Data x = null;
//		double value = 0.0d;
//		
//       // find x for which alpha is greater than 0 and less than 1
//		
//		for(int i=0; i<supportVectors.length;i++ ){
//			if(supportVectors[i]>0.0 && supportVectors[i]<1.0){
//				x = orderedData[i];break;
//			}
//		}
//		for(int i=0; i<supportVectors.length;i++ ){
//			
//			int sv = supportVectors[i].intValue();
//			Label l = orderedData[sv].getLabel();
//			value+= l.getValue()*alphas[i]*m.matrix[0][sv];
//		}
//		
//		b = x.getLabel().getValue() - value;
//		
//	}
	
	/** 
	 * extract the alpha coefficients which are not zero and the corresponding support vectors
	 **/

	private void setAlphas(double[] cfs) {
		
		List<Integer> list1 = new ArrayList<Integer>();
		List<Double> list2 = new ArrayList<Double>();
		for(int i =0; i<cfs.length; i++){
			if(cfs[i]>0){
				list1.add(i);
				list2.add(cfs[i]);
			}
		}
		Integer[]array1 = new Integer[list1.size()];
		supportVectors = list1.toArray(array1);
		Double[]array2 = new Double[list2.size()];
		alphas =  list2.toArray(array2);
		
	}
	
	public Double[] getAlphas(){
		
		return alphas;
	}

	/** 
	 * Prediction function:  sgn( sum (y(i)*alpha(i)*K(x(i); x)) + b)
	 **/
	@Override
	public Label getPrediction(Data x) {
		
		double prediction = 0.0d;
		Data[] orderedData = null;
		orderedData = dataset.getAllData();

		int index = 0;

		for(int n =0; n<orderedData.length;n++){
			if(orderedData[n].getSourceNode() == x.getSourceNode()&&
				orderedData[n].getTargetNode() == x.getTargetNode()){
				index=n; break;
			}
		}

			for(int i=0; i<supportVectors.length;i++ ){
				int sv = supportVectors[i].intValue();
				Label l = orderedData[sv].getLabel();
				prediction+= l.getValue()*alphas[i]*m.matrix[index][sv];

			}				
//			  prediction += b;
			  Label label = new Label();
			  label.setValue(prediction>0 ? 1.0 : -1.0);

    return label;
	}
}